package server;


import webWof.State;
import webWof.WebMessage;
import webWof.WebPhraseDB;
import webWof.WebPlayer;

import General.Phrase;

import java.io.Serializable;
public class ServerGame implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 4687854503653269075L;
	private static final int NumOfRounds = 4;
	private WebPlayer[] players;
	private WebLock[] locks;
	private boolean[] PlayingStatus;
	private int capacity;
	private Phrase phrase;
	private int round;
	private int uniqueID;
	private boolean isFull;
	private int pos = 0;
	private static int id = 0;
	private char[] lastGuessedLetters;
	private String[] lastGuessedExp;
	private WebPhraseDB phrases;
	private int numberOfActivePlayers;
	private boolean isGameEnded = false;
	
	public ServerGame(int cap){
		capacity = cap;
		numberOfActivePlayers = cap;
		uniqueID = generateID();
		players = new WebPlayer[capacity];
		locks = new WebLock[capacity];
		PlayingStatus = new boolean[capacity];
		lastGuessedLetters = new char[capacity];
		lastGuessedExp = new String[capacity];
		phrases = new WebPhraseDB();
		phrase = phrases.getNextPhrase();
		for(int i = 0;i<capacity;i++){
			locks[i] = new WebLock();
			locks[i].lock();
			lastGuessedExp[i] = "";
			lastGuessedLetters[i] = '#';
			PlayingStatus[i] = false;
		}
		locks[0].unlock();
		round = 0;
	}
	
	public  void addPlayer(WebPlayer player){
		player.state = State.PLAYING;
		players[pos++] = player;
		if (pos == capacity){
			isFull = true;
		}
	}

	public boolean isFull() {
		return isFull;
	}

	public int getID() {
		return uniqueID;
	}
	
	private static synchronized int  generateID(){
		return ++id;
	}

	public Phrase getPhrase(){
		return phrase;
	}
	
	public void setNextPhrase() {
		phrase = phrases.getNextPhrase();
	}

	public WebPlayer getPlayer(String PlayerName) {
		for(int i = 0;i< capacity;i++){
			if (players[i].getName().equalsIgnoreCase(PlayerName)){
				return players[i];
			}
		}
		return null;
	}

	public WebMessage createRoundEndMsg(WebMessage msg) {
		WebMessage retMsg = new WebMessage();
		//get the other player idx
		int idx = getPlayerIdx(msg.PlayerName);
		idx = (idx + 1)%capacity;
		//build the msg
		retMsg.opLetter = lastGuessedLetters[idx];
		retMsg.opScore = players[idx].score;
		retMsg.guessedExpression = lastGuessedExp[idx];
		retMsg.flag = true;
		retMsg.phrase = getPhrase();
		retMsg.roundNum = round;
		return retMsg;
	}

	public WebMessage createStartTurnMsg(WebMessage msg) {
		WebMessage retMsg = new WebMessage();
		//get the other player idx
		int idx = getPlayerIdx(msg.PlayerName);
		idx = (idx + 1)%capacity;
		//build the msg
		retMsg.opLetter = lastGuessedLetters[idx];
		retMsg.opScore = players[idx].score;
		retMsg.guessedExpression = lastGuessedExp[idx];
		retMsg.flag = false;
		retMsg.phrase = getPhrase();
		retMsg.roundNum = round;
		return retMsg;
		
	}

	public void setPhraseChanges(Phrase phrase2) {
		phrase = phrase2;
	}

	public void handleRoundEnded(WebMessage msg) {
		round++;
		proccessMsgContent(msg);
		if (round > NumOfRounds){
			phrase = null;
			for(int i = 0; i<capacity; i++){
				locks[i].unlock();
			}
		}
		else{
			setNextPhrase();
		}
		

	}

	private void proccessMsgContent(WebMessage msg) {
		int i = getPlayerIdx(msg.PlayerName);
		lastGuessedExp[i] = msg.guessedExpression;
		lastGuessedLetters[i] = msg.opLetter;
		players[i].score = msg.opScore;
		
		
	}

	private int getPlayerIdx(String name) {
		int i = 0;
		boolean isFound = false;
		for(;i< capacity;i++){
			if (players[i].name.equalsIgnoreCase(name)){
				isFound = true;
				break;
			}
		}
		if (!isFound)
			i  = -1;
		return i;
		
	}

	public WebMessage createEndTurnMsg(WebMessage msg) {
		return new WebMessage();
	}

	public void proccessEndTurnMsg(WebMessage msg) {
		proccessMsgContent(msg);
		setPhraseChanges(msg.phrase);
		
		
	}

	public void lockPlayer(String playerName) {
		int idx = getPlayerIdx(playerName);
		locks[idx].lock();
	
	}

	public int getRoundNum() {
		return round;
	}

	public WebPlayer getWinner() {
		WebPlayer retval = null;
		//todo: handle tie
		int maxScore = 0;
		for(int i =0;i<capacity; i++){
			if (maxScore < players[i].score){
				retval = players[i];
			}
		}
		return retval;
	}

	public boolean IsPlayerTurn(String playerName) {
		int i = getPlayerIdx(playerName);
		return !locks[i].isLocked();
	}

	public boolean IsPlayerPlaying(String playerName) {
		return PlayingStatus[getPlayerIdx(playerName)];
	}

	public void PlayerPlaying(String playerName) {
		int idx = getPlayerIdx(playerName);
		PlayingStatus[idx] = true;
		PlayingStatus[1-idx] = false;
	}
	
	public void setNotPlaying(String playerName){
		int idx = getPlayerIdx(playerName);
		PlayingStatus[idx] = false;
	}

	public void lockPlayerAndRealeseNext(String playerName) {
		int i = getPlayerIdx(playerName);
		locks[i].lock();
		locks[(i+1) % capacity].unlock();
		
	}

	public void removePlayer() {
		numberOfActivePlayers--;
	}
	public boolean canRemove(){
		return numberOfActivePlayers == 0;
	}

	public void forceEndTheGame() {
		isGameEnded = true;
		this.phrase = null;
		for(int i = 0 ; i < capacity ; i++){
			locks[i].unlock();
			PlayingStatus[i] = false;
		}
	}

	public boolean IsEnded() {
		return isGameEnded;
	}
	
	public WebPlayer getLoser() {
		WebPlayer winner = getWinner();
		for(WebPlayer p : players){
			if (!p.name.equalsIgnoreCase(winner.name)){
				return p;
			}
		}
		return null;
	}

}
